/**
 * Copyright 2006 Brad Reynolds
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.leeloo.core;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Immutable object that represents a name value pair.
 * 
 * @author Brad Reynolds
 */
public class Tag implements Comparable {
    /**
     * Display that represents the tag.
     */
    private String display;

    /**
     * Separator for display of the Tag.
     */
    public final static String DISPLAY_SEPARATOR = ":"; //$NON-NLS-1$

    /**
     * Identifier for the tag.
     */
    private final String name;

    /**
     * Value of the tag.
     */
    private final String value;

    /**
     * Pattern to match against for a tag with a name and value.
     */
    public final static Pattern NAME_VALUE_PATTERN = Pattern.compile("(.+):(.+)"); //$NON-NLS-1$
    
    /**
     * Constructs a new tag.
     * 
     * @param name
     * @param value can be <code>null</code>
     */
    public Tag(String name, String value) {
        if (name == null) {
            throw new IllegalArgumentException("Parameter name was null."); //$NON-NLS-1$ 
        }

        this.name = name;
        this.value = value;
    }
    
    /**
     * Creates a Tag from the display representation.
     * 
     * @param display
     * @return tag instance with the display representation
     * @throws IllegalArgumentException
     *             if the <code>display</code> doesn't match
     *             {@link #NAME_VALUE_PATTERN}
     */
    public static Tag fromDisplay(String display) {
        if (display == null) {
            throw new IllegalArgumentException("Parameter display was null."); //$NON-NLS-1$
        }

        Matcher matcher = NAME_VALUE_PATTERN.matcher(display);
        Tag result = null;
        if (matcher.matches()) {
            assert matcher.groupCount() == 2;
            result = new Tag(matcher.group(1), matcher.group(2));
        } else {
            throw new IllegalArgumentException("Display [" + display + "] is invalid."); //$NON-NLS-1$//$NON-NLS-2$
        }

        return result;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @return the value, can be <code>null</code>
     */
    public String getValue() {
        return value;
    }

    /**
     * @return returns the formatted display of the tag
     */
    public String getDisplay() {
        if (display == null) {
            display = new StringBuffer().append(name).append(DISPLAY_SEPARATOR).append(value).toString();
        }

        return display;
    }

    /**
     * Returns the display.
     * 
     * @see java.lang.Object#toString()
     */
    public String toString() {
        return getDisplay();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + ((name == null) ? 0 : name.hashCode());
        result = PRIME * result + ((value == null) ? 0 : value.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final Tag other = (Tag) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    public int compareTo(Object o) {
        if (o == null) {
            return 1;
        }
        
        return this.getName().compareTo(((Tag) o).getName());
    }
}